<%@ Page Language="C#" %>
<%@ Import namespace="SubSonic.Utilities"%>
<%@ Import Namespace="SubSonic" %>
<%
	//The data we need
	string providerName = "#PROVIDER#";
	string tableName = "#TABLE#";
	TableSchema.Table tbl = DataService.GetSchema(tableName, providerName, TableType.Table);
	DataProvider provider = DataService.Providers[providerName];
	ICodeLanguage lang = new CSharpCodeLanguage();

	TableSchema.TableColumnCollection cols = tbl.Columns;
	string className = tbl.ClassName;
	string thisPK = tbl.PrimaryKey.PropertyName;
	string varPK = tbl.PrimaryKey.ArgumentName;
	string varPKType = Utility.GetVariableType(tbl.PrimaryKey.DataType, tbl.PrimaryKey.IsNullable, lang);
  bool showGenerationInfo = false;
  bool useNullables = tbl.Provider.GenerateNullableProperties;
  
%>

<% if(showGenerationInfo)
   { %>
 //Generated on <%=DateTime.Now.ToString() %> by <%=Environment.UserName %>
<% }  %>
namespace <%=provider.GeneratedNamespace %>
{
	/// <summary>
	/// Strongly-typed collection for the <%=className%> class.
	/// </summary>

	[Serializable]
	public partial class <%=className%>Collection : AbstractList[<]<%=className %>,<%= className %>Collection[>]
	{	   
        public <%=className%>Collection() {}
	}

	/// <summary>
	/// This is an ActiveRecord class which wraps the <%=tableName%> table.
	/// </summary>
	[Serializable]
	public partial class <%=className%> : AbstractRecord[<]<%= className%>[>], 
	    IAbstractRecord,
	    System.Runtime.Serialization.ISerializable
	{
		#region .ctors and Default Settings
		
		public <%=className %>()
		{
		  SetSQLProps();
		  InitSetDefaults();
		  MarkNew();
		}
		
		private void InitSetDefaults() { SetDefaults(); }
		
		public <%=className %>(bool useDatabaseDefaults)
		{
			SetSQLProps();
			if(useDatabaseDefaults)
				ForceDefaults();
			MarkNew();
		}
	
		protected static void SetSQLProps() { GetTableSchema(); }
		
		#endregion
		
		#region ISerializable Members
				
		public <%=className %>(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
		{		    
		<% foreach (TableSchema.TableColumn col in cols)
            {
                string propName = col.PropertyName;
                string varType = Utility.GetVariableType(col.DataType, false, lang);
                string nullableVarType = Utility.GetVariableType(col.DataType, col.IsNullable, lang);
                if (varType != "string" && (useNullables && col.IsNullable) )
                   { %>
            if( (bool)info.GetValue("<%=propName %>HasValue", typeof(bool) ) )
                this.<%=propName %> = (<%=varType %>)info.GetValue("<%=propName %>", typeof(<%=varType %>));
            else
                this.<%=propName %> = null;
                <% } else { %>
            this.<%=propName %> = (<%=varType %>)info.GetValue("<%=propName %>", typeof(<%=varType %>));
                <% } %>
         <% } %>
		}

        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
        {
            base.GetObjectData(info, context);            
            <% foreach (TableSchema.TableColumn col in cols)
            {
                string propName = col.PropertyName;
                string varType = Utility.GetVariableType(col.DataType, false, lang);
                string nullableVarType = Utility.GetVariableType(col.DataType, col.IsNullable, lang);
                if (varType != "string" && (useNullables && col.IsNullable))
                   { %>
            if( this.<%=propName %>.HasValue ) {
                info.AddValue("<%=propName %>HasValue", true);
                info.AddValue("<%=propName %>", this.<%=propName %>.Value );
            }
            else {
                info.AddValue("<%=propName %>HasValue", false);                
            }
                <% } else { %>
                info.AddValue("<%=propName %>", this.<%=propName %> );            
                <% } %>
         <% } %>
        }

        #endregion
		
		#region Schema
		
		public static TableSchema.Table Schema
		{
			get
			{
				if (BaseSchema == null)
					SetSQLProps();
				return BaseSchema;
			}
		}
		
		private static void GetTableSchema() 
		{
			if(!IsSchemaInitialized)
			{
				//Schema declaration
				TableSchema.Table schema = new TableSchema.Table("<%=tableName%>", TableType.Table, DataService.GetInstance("<%=providerName%>"));
				schema.Columns = new TableSchema.TableColumnCollection();
				schema.SchemaName = @"<%=tbl.SchemaName%>";
				//columns
				<%
				foreach(TableSchema.TableColumn col in cols)
				{
					string varName = "col" + col.ArgumentName;
				%>
				TableSchema.TableColumn <%=varName %> = new TableSchema.TableColumn(schema);
				<%=varName %>.ColumnName = "<%=col.ColumnName%>";
				<%=varName %>.DataType = DbType.<%=col.DataType %>;
				<%=varName %>.MaxLength = <%=col.MaxLength %>;
				<%=varName %>.AutoIncrement = <%=col.AutoIncrement.ToString().ToLower() %>;
				<%=varName %>.IsNullable = <%=col.IsNullable.ToString().ToLower()%>;
				<%=varName %>.IsPrimaryKey = <%=col.IsPrimaryKey.ToString().ToLower()%>;
				<%=varName %>.IsForeignKey = <%=col.IsForeignKey.ToString().ToLower()%>;
				<%=varName %>.IsReadOnly = <%= col.IsReadOnly.ToString().ToLower() %>;
				<% if (!String.IsNullOrEmpty(col.DefaultSetting))					   
				%>
						<%=varName%>.DefaultSetting = @"<%= col.DefaultSetting%>";
				<%
				if(col.IsForeignKey) %>
					<%=varName %>.ForeignKeyTableName = "<%= col.ForeignKeyTableName %>";
				schema.Columns.Add(<%=varName%>);
				<%
				}
				%>
				BaseSchema = schema;

				//add this schema to the provider
				//so we can query it later
				DataService.Providers["<%=providerName %>"].AddSchema("<%=tableName%>",schema);
			}
		}
		#endregion
		
		#region "Props"
		
		<%			
			foreach(TableSchema.TableColumn col in cols)
			{
				string propName = col.PropertyName;
				string varType = Utility.GetVariableType(col.DataType, false, lang);
				string nullableVarType = Utility.GetVariableType(col.DataType, col.IsNullable, lang);

				if (useNullables || Utility.IsMatch(varType, nullableVarType))
				{
		%>  
		[XmlAttribute("<%=propName%>")]
		public <%=nullableVarType%> <%=propName%> 
		{
			get { return GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>"); }
			set { SetColumnValue("<%=col.ColumnName%>", value); }
		}
		<%
				}
			else
			{  
		%>
		
		//private <%= nullableVarType%> prop<%=propName%>;

		[XmlAttribute("<%=propName%>")]
		public <%= varType %> <%=propName%> 
		{
			get
			{
			<%= nullableVarType%> prop<%=propName%> = GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>");
				if (!prop<%=propName%>.HasValue)
					return <%= Utility.GetDefaultValue(col, lang)%>;
				return prop<%=propName%>.Value;
			}
		   set { SetColumnValue("<%=col.ColumnName%>", value); }
		}
		
		[XmlIgnore]
		public bool <%=propName%>HasValue
		{

			get { return GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>") != null; }
			set
			{
				<%= nullableVarType%> prop<%=propName%> = GetColumnValue[<]<%=nullableVarType%>[>]("<%=col.ColumnName%>");
				if (!value)
					SetColumnValue("<%=col.ColumnName%>", null);
				else if (value && !prop<%=propName%>.HasValue)
					SetColumnValue("<%=col.ColumnName%>", <%= Utility.GetDefaultValue(col, lang)%>);
		   }
		}
		
		<% 
			}
		}
		%>
		#endregion
		
		#region Columns Struct
		public struct Columns
		{
			<% foreach (TableSchema.TableColumn col in cols) {%> public /* static */ const string <%=col.PropertyName%> = @"<%=col.ColumnName%>";
			<%}%>			
		}
		#endregion
		
		<%if (tbl.PrimaryKeyTables.Count > 0)
{%>
		#region PrimaryKey Methods
		<%
	TableSchema.PrimaryKeyTableCollection pkTables = tbl.PrimaryKeyTables;
	if (pkTables != null)
	{
		ArrayList usedMethodNames = new ArrayList();
		foreach (TableSchema.PrimaryKeyTable pk in pkTables)
		{
			TableSchema.Table pkTbl = DataService.GetSchema(pk.TableName, providerName, TableType.Table);
			if (pkTbl.PrimaryKey != null && CodeService.ShouldGenerate(pkTbl))
			{
				string pkClass = pk.ClassName;
				string pkClassQualified = provider.GeneratedNamespace + "." + pkClass;
				string pkMethod = pk.ClassNamePlural;
				string pkColumn = pkTbl.GetColumn(pk.ColumnName).PropertyName;
				
				if (Utility.IsMatch(pkClass, pkMethod))
				{
					pkMethod += "Records";
				}

				if (pk.ClassName == className)
				{
					pkMethod = "Child" + pkMethod;
				}

				if (usedMethodNames.Contains(pkMethod))
				{
					pkMethod += "From" + className;
					if (usedMethodNames.Contains(pkMethod))
					{
						pkMethod += pkColumn;
					}
				}

				usedMethodNames.Add(pkMethod);
				
				if(!String.IsNullOrEmpty(provider.RelatedTableLoadPrefix))
				{
					pkMethod = provider.RelatedTableLoadPrefix + pkMethod;
				}

				bool methodsNoLazyLoad = !provider.GenerateRelatedTablesAsProperties && !provider.GenerateLazyLoads;
				bool methodsLazyLoad = !provider.GenerateRelatedTablesAsProperties && provider.GenerateLazyLoads;
				bool propertiesNoLazyLoad = provider.GenerateRelatedTablesAsProperties && !provider.GenerateLazyLoads;
				bool propertiesLazyLoad = provider.GenerateRelatedTablesAsProperties && provider.GenerateLazyLoads;

				if (methodsNoLazyLoad)
				{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>()
		{		    
		    return <%=pkClassQualified%>Controller.RemoteInstance.List(<%=pkClassQualified%>Controller.Query().AddWhere(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>));
			//return new <%=pkClassQualified%>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
		}
<%
			}
			else if (methodsLazyLoad)
			{
%>
		private <%= pkClassQualified %>Collection col<%=pkMethod%>;
		public <%= pkClassQualified %>Collection <%=pkMethod%>()
		{
			if(col<%=pkMethod%> == null) {
			    col<%=pkMethod%> = <%=pkClassQualified%>Controller.RemoteInstance.List(<%=pkClassQualified%>Controller.Query().AddWhere(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>));
				//col<%=pkMethod%> = new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
			}
			return col<%=pkMethod%>;
		}
<%
			}
			else if (propertiesNoLazyLoad)
			{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>
		{
			get { 
			    return <%=pkClassQualified%>Controller.RemoteInstance.List(<%=pkClassQualified%>Controller.Query().AddWhere(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>));
			    //return new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load(); 
			}
		}
<%
			}
			else if (propertiesLazyLoad)
			{
%>		
		private <%= pkClassQualified %>Collection col<%=pkMethod%>;
		public <%= pkClassQualified %>Collection <%=pkMethod%>
		{
			get
			{
				if(col<%=pkMethod%> == null) {
				    col<%=pkMethod%> = <%=pkClassQualified%>Controller.RemoteInstance.List(<%=pkClassQualified%>Controller.Query().AddWhere(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>));
					//col<%=pkMethod%> = new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
				}
				return col<%=pkMethod%>;			
			}
			set { col<%=pkMethod%> = value; }
		}
		<%
			}
		}
	}
}
%>
		#endregion
		<%   
	}
%>
			
		<%if (tbl.ForeignKeys.Count > 0) { %>
		#region ForeignKey Properties
		<%
			TableSchema.ForeignKeyTableCollection fkTables = tbl.ForeignKeys;

			if (fkTables != null)
			{
				ArrayList usedPropertyNames = new ArrayList();
				foreach (TableSchema.ForeignKeyTable fk in fkTables)
				{
					TableSchema.Table fkTbl = DataService.GetSchema(fk.TableName, providerName, TableType.Table);
					if (CodeService.ShouldGenerate(fkTbl))
					{
						string fkClass = fk.ClassName;
						string fkClassQualified = provider.GeneratedNamespace + "." + fkClass;
						string fkMethod = fk.ClassName;
						string fkID = tbl.GetColumn(fk.ColumnName).PropertyName;
						string fkColumnID = fk.ColumnName;

						//it's possible this table is "relatin to itself"
						//check to make sure the class names are not the same
						//if they are, use the fk columnName
						if (fk.ClassName == className)
						{
							fkMethod = "Parent" + fk.ClassName;
						}

						if (usedPropertyNames.Contains(fk.ClassName))
						{
							fkMethod += "To" + fkID;
						}

						if (tbl.GetColumn(fkMethod) != null)
						{
							fkMethod += "Record";
						}
%>
		/// <summary>
		/// Returns a <%=fkClass%> ActiveRecord object related to this <%=className%>
		/// 
		/// </summary>
		public <%=fkClassQualified%> <%=fkMethod%>
		{
			get { 
			    return <%=fkClassQualified%>Controller.RemoteInstance.Get(this.<%=fkID%>);
			    //return <%=fkClassQualified%>.FetchByID(this.<%=fkID%>); 
			}
			set { SetColumnValue("<%=fkColumnID%>", value.<%=fkTbl.PrimaryKey.PropertyName%>); }
		}
		
		<%
			usedPropertyNames.Add(fk.ClassName);
		}
	}
}
		%>
		#endregion
		<%} else {%>
		//no foreign key tables defined (<%=tbl.ForeignKeys.Count.ToString() %>)
		<%} %>
		
		
		#region IAbstractRecord Members
        
                          
        public new CT GetColumnValue[<]CT[>](string columnName) {
            return base.GetColumnValue[<]CT[>](columnName);
        }

        public object GetColumnValue(string columnName) {
            return base.GetColumnValue[<]object[>](columnName);
        }
        
        public new CT GetDefaultColumnValue[<]CT[>](string columnName) {
            return base.GetDefaultColumnValue[<]CT[>](columnName);
        }

        public object GetDefaultColumnValue(string columnName) {
            return base.GetDefaultColumnValue[<]object[>](columnName);
        }
        
        public new CT GetOriginalColumnValue[<]CT[>](string columnName) {
            return base.GetOriginalColumnValue[<]CT[>](columnName);
        }

        public object GetOriginalColumnValue(string columnName) {
            return base.GetOriginalColumnValue[<]object[>](columnName);
        }
        
                
        #endregion
        
	}
}
